package com.rpcLearning.server;

import com.rpcLearning.common.ReflectUtils;
import com.rpcLearning.proto.Request;
import com.rpcLearning.proto.Response;
import com.rpcLearning.transport.RequestHandler;
import com.rpcLearning.transport.TransportServer;
import com.rpclearnging.codec.Decoder;
import com.rpclearnging.codec.Encoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @author:zyh
 * @Time:2021-03-17-20:17
 * @email:1269231889@qq.com
 */
@Slf4j

public class RPCServer {
    private RPCServerConfig config;
    private TransportServer net;
    private Encoder encoder;
    private Decoder decoder;
    private ServiceManager serviceManager;
    private ServiceInvoker serviceInvoker;



    public  RPCServer(){
        this.config = new RPCServerConfig();
    }
    public RPCServer(RPCServerConfig config) {
        this.config = config;
        this.net = ReflectUtils.newInstance(
                config.getTransportClass());
        this.net.init(config.getPort(), this.handler);
        this.encoder = ReflectUtils.newInstance(
                config.getEncoderClass());
        this.decoder = ReflectUtils.newInstance(
                config.getDecoderClass());

        this.serviceInvoker = new ServiceInvoker();
        this.serviceManager = new ServiceManager();
    }

    public <T> void register(Class<T> interfaceClass, T bean) {
        serviceManager.register(interfaceClass, bean);
    }

    public void start() {
        this.net.start();
    }

    public void close() {
        this.net.close();
    }
    private RequestHandler handler = new RequestHandler() {
        //从rec中读取request的数据体，然后通过serviceInvoker调用服务，最后通过Response写回OutStream
        @Override
        //从rec中读取request的数据体，然后通过serviceInvoker调用服务，最后通过Response写回OutStream
        public void onRequest(InputStream rec, OutputStream out) {
            Response response = new Response();
            try {
                byte[] bytes = IOUtils.readFully(rec, rec.available());
                Request request = decoder.decoder(bytes, Request.class);

                ServiceInstance lookup = serviceManager.lookup(request);
                Object invoker = serviceInvoker.invoker(lookup, request);
                log.info("get request: {}",request);
                response.setData(invoker);
            } catch (Exception e) {
                log.warn(e.getMessage(), e);
                response.setStatus(1);
                response.setMessage("get error" + e.getClass().getName() + " " + e.getMessage());
            } finally {
                try {
                    byte[] encode = encoder.encode(response);
                    out.write(encode);

                    log.info("response client");
                } catch (IOException e) {
                    log.warn(e.getMessage(), e);
                }
            }
        }
    };

}
